package com.yehui.spring.lifecycle;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.Lifecycle;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;

import java.io.IOException;

/**
 * @author 业徽
 * @date 2021/6/28
 */
public class LifecycleDemo {

    @EventListener
    public void contextRefreshedEvent(ContextRefreshedEvent event) {
        System.out.println("ContextRefreshedEvent");
    }

    @EventListener
    public void contextRefreshedEvent(ContextStartedEvent event) {
        System.out.println("ContextStartedEvent");
    }

    @EventListener
    public void contextRefreshedEvent(ContextStoppedEvent event) {
        System.out.println("ContextStoppedEvent");
    }

    /**
     * SmartLifecycle 是 autoStartUp 的，在 refresh 阶段就会触发 start 方法
     *
     * @return
     */
    @Bean
    public SmartLifecycle smartLifecycle() {
        return new SmartLifecycle() {

            private boolean start = false;

            /**
             * Start this component.
             * <p>Should not throw an exception if the component is already running.
             * <p>In the case of a container, this will propagate the start signal to all
             * components that apply.
             *
             * @see SmartLifecycle#isAutoStartup()
             */
            @Override
            public void start() {
                System.out.println("SmartLifecycle start");
                start = true;
            }

            /**
             * Stop this component, typically in a synchronous fashion, such that the component is
             * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle}
             * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary.
             * <p>Note that this stop notification is not guaranteed to come before destruction:
             * On regular shutdown, {@code Lifecycle} beans will first receive a stop notification
             * before the general destruction callbacks are being propagated; however, on hot
             * refresh during a context's lifetime or on aborted refresh attempts, a given bean's
             * destroy method will be called without any consideration of stop signals upfront.
             * <p>Should not throw an exception if the component is not running (not started yet).
             * <p>In the case of a container, this will propagate the stop signal to all components
             * that apply.
             *
             * @see SmartLifecycle#stop(Runnable)
             * @see DisposableBean#destroy()
             */
            @Override
            public void stop() {
                System.out.println("SmartLifecycle stop");
                start = false;
            }

            /**
             * Check whether this component is currently running.
             * <p>In the case of a container, this will return {@code true} only if <i>all</i>
             * components that apply are currently running.
             *
             * @return whether the component is currently running
             */
            @Override
            public boolean isRunning() {
                return start;
            }
        };
    }

    /**
     * Lifecycle 是非 autoStartUp 的，在 start 阶段触发 start 方法
     *
     * @return
     */
    @Bean
    public Lifecycle lifecycle() {
        return new Lifecycle() {

            private boolean start = false;

            /**
             * Start this component.
             * <p>Should not throw an exception if the component is already running.
             * <p>In the case of a container, this will propagate the start signal to all
             * components that apply.
             *
             * @see SmartLifecycle#isAutoStartup()
             */
            @Override
            public void start() {
                System.out.println("Lifecycle start");

                start = true;
            }

            /**
             * Stop this component, typically in a synchronous fashion, such that the component is
             * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle}
             * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary.
             * <p>Note that this stop notification is not guaranteed to come before destruction:
             * On regular shutdown, {@code Lifecycle} beans will first receive a stop notification
             * before the general destruction callbacks are being propagated; however, on hot
             * refresh during a context's lifetime or on aborted refresh attempts, a given bean's
             * destroy method will be called without any consideration of stop signals upfront.
             * <p>Should not throw an exception if the component is not running (not started yet).
             * <p>In the case of a container, this will propagate the stop signal to all components
             * that apply.
             *
             * @see SmartLifecycle#stop(Runnable)
             * @see DisposableBean#destroy()
             */
            @Override
            public void stop() {
                System.out.println("Lifecycle stop");
                start = false;
            }

            /**
             * Check whether this component is currently running.
             * <p>In the case of a container, this will return {@code true} only if <i>all</i>
             * components that apply are currently running.
             *
             * @return whether the component is currently running
             */
            @Override
            public boolean isRunning() {
                return start;
            }
        };
    }

    public static void main(String[] args) throws IOException {

        final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(LifecycleDemo.class);

        System.out.println("refresh");
        applicationContext.refresh();
        System.out.println("start");
        applicationContext.start();
        applicationContext.stop();
        applicationContext.close();
    }


}
